// @copyright Copyright (c) 2022 OnMicro Corp.
// @brief     RISC-V (rv32im) SoC demo w/o JTAG testbench file.
// @author    admin@ultra-embedded.com
//            wei.lu@onmicro.com.cn
// @license   SPDX-License-Identifier: Apache-2.0
`ifndef verilator
`timescale 1ns / 100ps
`endif

module tb_ue_soc
(
`ifdef verilator
     input sys_clk
`endif
);

//-----------------------------------------------------------------
// Clock
//-----------------------------------------------------------------
`ifndef verilator
reg sys_clk;
`endif

//-----------------------------------------------------------------
// Reset
//-----------------------------------------------------------------
reg ue_soc_rst;

//-----------------------------------------------------------------
// Core
//-----------------------------------------------------------------

ue_soc_top
#(
    .CLK_FREQ(50000000)
   ,.BAUDRATE(1000000)   // SoC UART baud rate
   ,.UART_SPEED(1000000) // Debug bridge UART baud (should match BAUDRATE)
   ,.C_SCK_RATIO(50)     // SPI clock divider (SPI_CLK=CLK_FREQ/C_SCK_RATIO)
`ifdef CPU_SELECT_ARMV6M
   ,.CPU("armv6m")       // riscv or armv6m
`else
   ,.CPU("riscv")        // riscv or armv6m
`endif
)
u_top
(
     .clk_i(sys_clk)
    ,.rst_i(ue_soc_rst)

    // SPI
    ,.spi_clk_o()
    ,.spi_mosi_o()
    ,.spi_cs_o()
    ,.spi_miso_i(1'b0)

    // GPIO
    ,.gpio_output_o()
    ,.gpio_output_enable_o()
    ,.gpio_input_i(32'b0)

    // UART
    ,.dbg_rxd_o()
    ,.dbg_txd_i(1'b1)
    ,.uart_rx_i(1'b1)
    ,.uart_tx_o()
);

integer tb_idx;
`ifdef verilator
integer main_cycles = 0;
`endif

// Verilog stimulus
`include "stimulus.v"

//
// Initialize Memory
//------------------------------
initial
begin
    // Initialize dual port ram
    for (tb_idx=0; tb_idx < 2048; tb_idx=tb_idx+1)
       u_top.u_cpu.u_tcm.u_ram.ram[tb_idx] = 32'h00000000 + tb_idx;
`ifdef verilator
    $readmemh("../rom.mem", u_top.u_cpu.u_tcm.u_ram.ram);
`else
    //#10 $readmemh("./rom.mem", u_top.riscv_tcm_wrapper.tcm_mem.tcm_mem_ram.ram);
    //#10 $readmemh("./rom.mem", u_top.u_cpu.u_tcm.u_ram.ram, 32'h800);
    #10 $readmemh("./rom.mem", u_top.u_cpu.u_tcm.u_ram.ram);
`endif
    $display("[%t][Simulator] DPRAM is loaded.", $time);
    $fflush();
end

//
// Generate wave file, used by gtkwave
//------------------------------
`ifndef NO_DUMP
initial
begin
    $dumpfile("tb_ue_soc.vcd");
    $dumpvars(0, tb_ue_soc);
end
`endif

//
// Generate Clock
//------------------------------
`ifndef verilator
initial
begin
    sys_clk          = 1'b0;
    forever
    begin
        #25;   // 20 MHz
        sys_clk = ~sys_clk;
    end
end
`endif //  `ifndef verilator

initial
begin
    $display("[%t][Simulator] Simulation is started.", $time);
    $fflush();

    //---------------------------------------
    // Generate stimulus
    //---------------------------------------

    //rst_i    : Async reset, active-high. Reset memory / AXI interface.
    ue_soc_rst                      = 1'b1;

    //rst_cpu_i: Async reset, active-high. Reset CPU core (excluding AXI / memory).
    //write32(GPIO_ADDR=0xF0000000, 0x0);
    //write32(GPIO_ADDR=0xF0000000, 0x1);
    force u_top.rst_cpu_w           = 1'b1;

`ifndef verilator
    //Don't use #10, otherwise the reset assert time is too short, < half of sys_clk.
    #100;
    ue_soc_rst    = 1'b0;
    $display("[%t][Simulator] Reset (Memory/AXI) is released.", $time);
    #100
    force u_top.rst_cpu_w = 1'b0;
    $display("[%t][Simulator] Reset (CPU) is released.", $time);
    $fflush();
`endif
end

`ifdef verilator
always @ (posedge sys_clk)
begin
    main_cycles = main_cycles + 1;
    if (main_cycles == 10) begin
        ue_soc_rst = 1'b0;
    end
    else if (main_cycles == 20) begin
        force u_top.rst_cpu_w = 1'b0;
        $display("[%t][Simulator] Reset is released.", $time);
        $fflush();
    end
`ifdef NO_TIMEOUT
`else
    if (main_cycles > 500000) begin
        $display("[%t][Simulator] Simulation is done due to TIMEOUT.", $time);
        $finish;
    end
`endif
end
`else
initial
begin
`ifdef NO_TIMEOUT
`else
    #5000000
    $display("[%t][Simulator] Simulation is done due to TIMEOUT.", $time);
    $finish;
`endif
end
`endif

endmodule // tb_ue_soc
